/*
 * Tencent is pleased to support the open source community by making QMUI_Android available.
 *
 * Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
 *
 * Licensed under the MIT License (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 *
 * http://opensource.org/licenses/MIT
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.github.leon406.view.span;

import android.text.Layout;
import android.text.Selection;
import android.text.Spannable;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.TextView;
import io.github.leon406.view.textview.ISpanTouch;
import java.lang.ref.WeakReference;

/**
 * @author cginechen
 * @date 2017-03-20
 */
public class LinkTouchDecorHelper {
    private static final String TAG = "QMUILinkTouch";
    private WeakReference<ITouchableSpan> mPressedSpanRf;

    public boolean onTouchEvent(TextView textView, Spannable spannable, MotionEvent event) {

        ITouchableSpan touchedSpan;
        ITouchableSpan recordSpan = null;
        switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                touchedSpan = getPressedSpan(textView, spannable, event);
                if (touchedSpan != null) {
                    touchedSpan.setPressed(true);
                    Selection.setSelection(
                            spannable,
                            spannable.getSpanStart(touchedSpan),
                            spannable.getSpanEnd(touchedSpan));
                    mPressedSpanRf = new WeakReference<>(touchedSpan);
                }
                if (textView instanceof ISpanTouch) {
                    ISpanTouch tv = (ISpanTouch) textView;
                    tv.setTouchSpanHit(touchedSpan != null);
                }
                return touchedSpan != null;
            case MotionEvent.ACTION_MOVE:
                touchedSpan = getPressedSpan(textView, spannable, event);
                if (mPressedSpanRf != null) {
                    recordSpan = mPressedSpanRf.get();
                }

                if (recordSpan != null && recordSpan != touchedSpan) {
                    recordSpan.setPressed(false);
                    mPressedSpanRf = null;
                    recordSpan = null;
                    Selection.removeSelection(spannable);
                }
                if (textView instanceof ISpanTouch) {
                    ISpanTouch tv = (ISpanTouch) textView;
                    tv.setTouchSpanHit(recordSpan != null);
                }
                return recordSpan != null;
            case MotionEvent.ACTION_UP:
                boolean touchSpanHint = false;
                if (mPressedSpanRf != null) {
                    recordSpan = mPressedSpanRf.get();
                }
                if (recordSpan != null) {
                    touchSpanHint = true;
                    recordSpan.setPressed(false);
                    if (event.getActionMasked() == MotionEvent.ACTION_UP) {
                        recordSpan.onClick(textView);
                    }
                }

                mPressedSpanRf = null;
                Selection.removeSelection(spannable);
                if (textView instanceof ISpanTouch) {
                    ISpanTouch tv = (ISpanTouch) textView;
                    tv.setTouchSpanHit(touchSpanHint);
                }
                return touchSpanHint;

            default:
                if (mPressedSpanRf != null) {
                    recordSpan = mPressedSpanRf.get();
                }
                if (recordSpan != null) {
                    recordSpan.setPressed(false);
                }
                if (textView instanceof ISpanTouch) {
                    ISpanTouch tv = (ISpanTouch) textView;
                    tv.setTouchSpanHit(false);
                }
                mPressedSpanRf = null;
                Selection.removeSelection(spannable);
                return false;
        }
    }

    public ITouchableSpan getPressedSpan(
            TextView textView, Spannable spannable, MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();
        x -= textView.getTotalPaddingLeft();
        y -= textView.getTotalPaddingTop();

        x += textView.getScrollX();
        y += textView.getScrollY();

        Layout layout = textView.getLayout();
        int line = layout.getLineForVertical(y);
        /*
         * BugFix: https://issuetracker.google.com/issues/113348914
         */
        try {
            int off = layout.getOffsetForHorizontal(line, x);
            if (x < layout.getLineLeft(line) || x > layout.getLineRight(line)) {
                off = -1;
            }
            ITouchableSpan[] link = spannable.getSpans(off, off, ITouchableSpan.class);

            ITouchableSpan touchedSpan = null;
            if (link.length > 0) {
                touchedSpan = link[0];
            }
            return touchedSpan;
        } catch (IndexOutOfBoundsException e) {
            Log.d(TAG, "getPressedSpan", e);
        }
        return null;
    }
}
